package com.yuma.tingshu.album.config;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yuma.tingshu.album.mapper.AlbumInfoMapper;
import com.yuma.tingshu.album.mapper.TrackInfoMapper;
import com.yuma.tingshu.common.constant.RedisConstant;
import com.yuma.tingshu.model.album.AlbumInfo;
import com.yuma.tingshu.model.album.TrackInfo;
import jakarta.annotation.Resource;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RCountDownLatch;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.List;
import java.util.concurrent.ExecutorService;

@Configuration
public class BloomFilterConfig {

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private AlbumInfoMapper albumInfoMapper;

    @Autowired
    private TrackInfoMapper trackInfoMapper;

    @Resource(name = "commonThreadPoolConfig")
    private ExecutorService executorService;

    @Bean("albumBloomFilter")
    public RBloomFilter bloomFilter() throws InterruptedException {
        // 1.通过RedissonClient 创建布隆过滤器(字符串) 布隆过滤器方法类似于集合的方法
        RBloomFilter<String> bloomFilter = this.redissonClient.getBloomFilter(RedisConstant.ALBUM_BLOOM_FILTER);
        // 2.设置精度因子
        /**
         * 第一个参数是二进制数组长度
         * 第二个参数是误判率:0.03，正确率就是97%
         */
        bloomFilter.tryInit(300000, 0.03);

        // 3.向布隆过滤器中初始化数据
        // 获取总记录数
        Long count = albumInfoMapper.selectCount(null);
        // 每页100条数据
        int pageSize = 100;
        // 总页数
        long totalPage = count / pageSize;
        totalPage = count % pageSize == 0 ? totalPage : totalPage + 1;

        // 使用分布式CountDownLatch
        RCountDownLatch countDownLatch = this.redissonClient.getCountDownLatch(RedisConstant.ALBUM_BLOOM_LATCH);
        countDownLatch.trySetCount(totalPage);

        // 从第一页遍历到最后一页，进行分页查询
        for (int pageNum = 1; pageNum <= totalPage; pageNum++) {
            // 为了提高效率使用了线程池
            int finalPageNum = pageNum;
            executorService.execute(() -> {
                // 添加所有专辑id，放入布隆过滤器
                Page<AlbumInfo> albumInfoPage = this.albumInfoMapper.selectPage(new Page<>(finalPageNum, pageSize), null);
                List<AlbumInfo> albumInfos = albumInfoPage.getRecords();
                // 遍历当前页数据放入布隆过滤器
                albumInfos.forEach(albumInfo -> {
                    bloomFilter.add(RedisConstant.ALBUM_INFO_PREFIX + albumInfo.getId());
                });
                // 次数倒数-1
                countDownLatch.countDown();
            });
        }

        // 防止线程没执行完，先返回了，使用CountDownLatch
        countDownLatch.await();

        // TODO: 声音的数据

        // TODO: 分类数据
        return bloomFilter;
    }

    @Bean("trackBloomFilter")
    public RBloomFilter bloomFilter2() throws InterruptedException {
        RBloomFilter<Object> bloomFilter = redissonClient.getBloomFilter(RedisConstant.TRACK_BLOOM_FILTER);
        bloomFilter.tryInit(200000,0.03);
        Long count = trackInfoMapper.selectCount(null);
        int pageSize = 100;
        long totalPage = count / pageSize;
        totalPage = count % pageSize == 0 ? totalPage : totalPage + 1;

        RCountDownLatch countDownLatch = this.redissonClient.getCountDownLatch(RedisConstant.TRACK_BLOOM_LATCH);
        countDownLatch.trySetCount(totalPage);

        for (int pageNum = 1; pageNum <= totalPage; pageNum++){
            int finalPageNum = pageNum;
            executorService.execute(() -> {
                Page<TrackInfo> trackInfoPage = trackInfoMapper.selectPage(new Page<>(finalPageNum, pageSize), null);
                List<TrackInfo> trackInfos = trackInfoPage.getRecords();
                trackInfos.forEach(trackInfo -> {
                    bloomFilter.add(RedisConstant.TRACK_INFO_PREFIX + trackInfo.getId());
                });
                countDownLatch.countDown();
            });
        }

        countDownLatch.await();

        return bloomFilter;
    }
}